/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package main.ContextFree;

import dk.brics.automaton.Automaton;
import dk.brics.automaton.RegExp;
import dk.brics.automaton.State;
import dk.brics.automaton.Transition;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Stack;

/**
 *
 * @author Isaac Osesina
 */
public class RegexToAutomaton implements Serializable, Cloneable{

    String regex;
    RegExp regExp;
    Automaton automaton;

    public RegexToAutomaton(String regex) {
        this.regex = regex;
        this.regExp = new RegExp(regex);
        automaton = regExp.toAutomaton();
    }

    public Automaton getAutomaton() {
        return automaton;
    }

    public void setAutomaton(Automaton automaton) {
        this.automaton = automaton;
    }

    public RegExp getRegExp() {
        return regExp;
    }

    public void setRegExp(RegExp regExp) {
        this.regExp = regExp;
    }

    public String getRegex() {
        return regex;
    }

    public void setRegex(String regex) {
        this.regex = regex;
    }

    public boolean isComplement(Automaton b) {
        boolean subsetOf = automaton.subsetOf(b);
        if(subsetOf) {
            return subsetOf;
        }
        else {
            subsetOf = b.subsetOf(automaton);
            return subsetOf;
        }
    }

    public boolean isComplement(String  regex) {
        return isComplement(regexConvertToAutomaton(regex));
    }

    private Automaton regexConvertToAutomaton(String regex) {
        RegExp  exp = new RegExp(regex);
        return exp.toAutomaton();
    }

    public boolean isOverlap(String regex) {
        return isOverlap( regexConvertToAutomaton(regex) );
    }

    public boolean isOverlap(Automaton a) {
        Automaton union = automaton.union(a);
        Automaton union_min = automaton.union(a);
        union_min.minimize();
        if( union.getNumberOfTransitions()==union_min.getNumberOfTransitions() ) {
               ArrayList<Character> charsMin = getTransistionChar(union_min, true);
               ArrayList<Character> charsMax = getTransistionChar(union_min, false);
                boolean containsAllMin = listContainsMultiple(getTransistionChar(union, true), charsMin);
                boolean containsAllMax = listContainsMultiple(getTransistionChar(union, false), charsMax);
               if( containsAllMin && containsAllMax ) {
                   return false;
               }
        }
        return true;
    }

     public boolean listContainsMultiple(ArrayList<Character> a, ArrayList<Character> b) {
         Stack<Character> a1 = new Stack<Character>();
         ArrayList<Character> b1 = new ArrayList<Character>(b);
         for(Character aa:a)
             a1.push(aa);
         
         boolean found = true;
         while(!a1.isEmpty() && !b1.isEmpty() && found) {
             if( b1.contains(a1.peek()) ) {
                Character pop = a1.pop();
                 b1.remove(pop);
             }
             else {
                 found = false;
             }
         }
         return found;
     }


    public ArrayList<Character> getTransistionChar(Automaton a, boolean min) {
        ArrayList<Character> chars = new ArrayList<Character>();
            for(State s:a.getLiveStates()) {
                for(Transition t:s.getSortedTransitions(true)) {
                    if(min){
                        if(t.getMin() != '\u0000') {
                            chars.add(t.getMin());
                        }
                    }
                    else {
                        if(t.getMax() != '\u0000') {
                            chars.add(t.getMax());
                        }
                }
            }
        }
        return chars;
    }
    

    public  static void main(String[] args) {

        String regex1 = "[abc]{0,1}[def][ghi]";
        String regex2 = "[def]";//"[abc0-9][0-4][jkl]";

        RegexToAutomaton r2a = new RegexToAutomaton(regex1);
        RegexToAutomaton r2a2 = new RegexToAutomaton(regex2);
        boolean overlap = r2a.isOverlap(r2a2.automaton);
    }
}
